/**
 * @file mainwindow.h
 * @brief 声明了 MainWindow 类及全局辅助函数。
 *
 * MainWindow 类负责处理UDP文件传输的用户界面和核心逻辑。
 * 全局辅助函数用于格式化文件大小和传输速度。
 */
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QString> // 需要包含 QString 用于辅助函数声明
#include <QUdpSocket>
#include <QFile>
#include <QTimer>
#include <QPushButton>
#include <QLineEdit>
#include <QProgressBar>
#include <QTextEdit>
#include <QLabel>
#include <QElapsedTimer>
#include <QSet> // 用于跟踪接收到的包序号

// 全局辅助函数的声明
// 这样其他包含此头文件的 .cpp 文件就能找到它们
/**
 * @brief 格式化文件大小为可读字符串 (B, KB, MB, GB)。
 * @param bytes 文件大小（以字节为单位）。
 * @return 格式化后的文件大小字符串。
 * @see ::formatFileSize(qint64) for implementation details in mainwindow.cpp.
 */
QString formatFileSize(qint64 bytes);
/**
 * @brief 格式化传输速度为可读字符串 (B/s, KB/s, MB/s)。
 * @param bytes 传输的字节数。
 * @param milliseconds 传输所用的毫秒数。
 * @return 格式化后的传输速度字符串。
 * @see ::formatSpeed(qint64, qint64) for implementation details in mainwindow.cpp.
 */
QString formatSpeed(qint64 bytes, qint64 milliseconds);

QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE

/**
 * @brief 主窗口类，负责UDP文件传输的UI和逻辑。
 *
 *此类实现了UDP文件发送和接收的功能，包括文件选择、
 *目标IP和端口设置、传输进度显示、速度计算以及取消传输等功能。
 *它使用QUdpSocket进行网络通信，并通过自定义的协议进行数据包的收发和确认。
 */
class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    /**
     * @brief MainWindow 类的构造函数。
     * @param parent 父QWidget指针，默认为nullptr。
     */
    MainWindow(QWidget *parent = nullptr);
    /**
     * @brief MainWindow 类的析构函数。
     */
    ~MainWindow();

private slots:
    /** @brief “选择文件”按钮点击事件处理槽函数。 */
    void on_btnSelectFile_clicked();
    /** @brief “取消传输”按钮点击事件处理槽函数。 */
    void on_btnCancelTransfer_clicked();

    /** @brief “发送文件”按钮点击事件处理槽函数。 */
    void on_btnSend_clicked();
    /** @brief “开始接收”按钮点击事件处理槽函数。 */
    void on_btnReceive_clicked();

    /** @brief UDP套接字收到数据时的处理槽函数。 */
    void onReadyRead();
    /** @brief 发送端超时重传定时器的处理槽函数。 */
    void onTimeout();
    /** @brief 更新发送速度显示的定时器处理槽函数。 */
    void updateTransferSpeedDisplay();

private:
    // 注意：成员变量的声明顺序最好与构造函数初始化列表的顺序一致，以避免 -Wreorder 警告
    // UI相关指针通常先声明，然后是核心逻辑组件，再是状态变量等。
    // 这里我将按照一个逻辑分组进行排序，并在构造函数中对应调整。

    Ui::MainWindow *ui; ///< 指向由Qt Designer生成的UI类的指针，如果未使用.ui文件则为nullptr。

    // 网络核心组件
    QUdpSocket *udpSocket; ///< 用于UDP通信的套接字。

    // 发送端相关成员变量
    QFile *file;                   ///< 指向当前正在发送的文件的 QFile 对象。
    QString filePath;              ///< 当前选择的待发送文件的完整路径。
    int packetSize;                ///< 发送时每个数据包的数据部分的目标大小（字节）。
    quint32 totalPackets;          ///< 发送当前文件所需的总数据包数量。
    quint32 currentPacket;         ///< 当前正在发送或等待ACK的数据包序号（从0开始）。
    QTimer *timer;                 ///< 发送端用于超时和重传的定时器。
    QString targetIP;              ///< 目标接收端的IP地址字符串。
    quint16 targetPort;            ///< 目标接收端的端口号。
    bool sendingFileActive;        ///< 标志，为 true 时表示正在进行文件发送操作。

    // 接收端相关成员变量
    QFile *outputFile_R;               ///< 指向接收到的文件数据的 QFile 对象。
    QString outputFilePath_R;          ///< 接收文件时选择的保存路径。
    quint32 expectedTotalPackets_R;    ///< 从收到的第一个数据包中获取的期望总包数。
    QSet<quint32> receivedPacketIndices_R; ///< 存储已成功接收并写入的数据包序号的集合，用于处理乱序和重复包。
    bool receivingFileActive;          ///< 标志，为 true 时表示正在进行文件接收操作。

    // UI控件指针 (在构造函数中通过代码创建)
    // 这些指针的声明顺序可以根据UI布局或创建顺序来组织
    QPushButton *btnSelectFile;    ///< “选择文件”按钮。
    QLineEdit *editFilePath;       ///< 显示和编辑选定文件路径的行编辑器。
    QLineEdit *editTargetIP;       ///< 输入目标IP地址的行编辑器。
    QLineEdit *editTargetPort;     ///< 输入目标端口号的行编辑器。
    QPushButton *btnSend;          ///< “发送文件”按钮。
    QPushButton *btnReceive;       ///< “开始接收”按钮。
    QPushButton *btnCancelTransfer;///< “取消传输”按钮。
    QProgressBar *progressBar;     ///< 显示文件传输进度的进度条。
    QTextEdit *textLog;            ///< 显示操作日志和状态信息的文本编辑器。
    QLabel *labelFileSize;         ///< 显示选定文件大小或接收进度的标签。
    QLabel *labelTransferSpeed;    ///< 显示当前传输速度的标签。

    // 速度和传输时长计算相关
    QTimer *speedUpdateTimer;          ///< 定时器，用于周期性更新传输速度的显示。
    QElapsedTimer transferDurationTimer; ///< 记录传输已用时间的计时器。
    /**
     * @brief 在当前速度更新间隔内已发送（并确认）的字节数。
     * @note 在构造函数的成员初始化列表中，此成员的顺序应与其他成员协调，以避免潜在的 -Wreorder 编译器警告。
     */
    qint64 bytesSentInCurrentInterval;

    // 私有辅助函数
    // 发送逻辑
    /**
     * @brief 发送指定序号的数据包。
     * @param seq 要发送的数据包的序号（从0开始）。
     */
    void sendPacket(quint32 seq);
    /**
     * @brief 处理接收到的ACK确认包。
     * @param ackDatagram 包含ACK信息的原始数据报。
     * @param sender 发送ACK包的主机地址。
     * @param senderPort 发送ACK包的端口号。
     */
    void handleAckPacket(const QByteArray &ackDatagram, const QHostAddress &sender, quint16 senderPort);

    // 接收逻辑
    /**
     * @brief 处理接收到的数据包（非ACK包）。
     * @param dataDatagram 包含文件数据的数据报。
     * @param sender 发送数据包的主机地址。
     * @param senderPort 发送数据包的端口号。
     */
    void handleReceiveData(const QByteArray &dataDatagram, const QHostAddress &sender, quint16 senderPort);

    // 状态清理与UI更新
    /**
     * @brief 清理发送端的状态和资源。
     * @param transferCompletedSuccessfully 布尔值，指示传输是否成功完成。默认为false。
     */
    void cleanupSenderState(bool transferCompletedSuccessfully = false);
    /**
     * @brief 清理接收端的状态和资源。
     * @param transferCompletedSuccessfully 布尔值，指示传输是否成功完成。默认为false。
     * @param userCancelled 布尔值，指示是否是用户主动取消了接收。默认为false。
     */
    void cleanupReceiverState(bool transferCompletedSuccessfully = false, bool userCancelled = false);
    /**
     * @brief 重置UI元素到空闲状态。
     */
    void resetUiToIdleState();
    /**
     * @brief 根据传输是否活动来更新UI控件的启用/禁用状态。
     * @param active 布尔值，true表示传输正在进行。
     */
    void updateUiForActiveTransfer(bool active);
};
#endif // MAINWINDOW_H